//////////////////////////////////////////////////////////////////////////
//
// This file is a part of UKROP project.
// Copyright (c) Vladimir Gumenuk
//
// PROJECT:         Xort Custom Debug Engine
// FILE:            DebugProperty.h : Declaration of the CDebugProperty
// AUTHOR:          Vladimir Gumenuk
// DATE:            5-Jan-2013
// MODIFICATIONS:
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#define DBG_PROP_UNKNOWN      0
#define DBG_PROP_STKREG_ROOT  1
#define DBG_PROP_STKREG       2
#define DBG_PROP_LOCALVAR     3
#define DBG_PROP_GLOBALSYMBOL 4
#define DBG_PROP_SELFPTR      5

class CPropertyInfo : public DEBUG_PROPERTY_INFO
{
    DWORD  m_dwRefCount;
public:
    DWORD AddRef() {
        return ++m_dwRefCount;
    }
    DWORD Release() {
        if( --m_dwRefCount == 0 ) {
            delete this;
            return 0;
        }
        return m_dwRefCount;
    }
    CPropertyInfo() {
        dwFields        = 0;
        bstrFullName    = NULL;
        bstrName        = NULL;
        bstrType        = NULL;
        bstrValue       = NULL;
        pProperty       = NULL;
        dwAttrib        = 0;
        m_dwRefCount    = 0;
    }
    virtual ~CPropertyInfo() {
        SAFE_FREESTR( bstrFullName );
        SAFE_FREESTR( bstrName );
        SAFE_FREESTR( bstrType );
        SAFE_FREESTR( bstrValue );
        SAFE_RELEASE( pProperty );
    }

    void Copy( DEBUG_PROPERTY_INFO *dst )
    {
        dst->dwFields        = dwFields;
        dst->bstrFullName    = bstrFullName ? SysAllocString( bstrFullName ) : NULL;
        dst->bstrName        = bstrName ? SysAllocString( bstrName ) : NULL;
        dst->bstrType        = bstrType ? SysAllocString( bstrType ) : NULL;
        dst->bstrValue       = bstrValue ? SysAllocString( bstrValue ) : NULL;
        dst->pProperty       = pProperty;
        if( dst->pProperty ) dst->pProperty->AddRef();
        dst->dwAttrib        = dwAttrib;
    }
};

typedef IDebugProperty2* LPDEBUGPROPERTY2;
typedef xlist< LPDEBUGPROPERTY2, CCopyObject<LPDEBUGPROPERTY2>, CDeleteObject<LPDEBUGPROPERTY2> >   PROPERTIES_LIST;

//////////////////////////////////////////////////////////////////////////
// CDebugProperty
class ATL_NO_VTABLE CDebugProperty :
	public CComObjectRootEx<CComSingleThreadModel>,
	public CComCoClass<CDebugProperty, &CLSID_DebugProperty>,
	public IDebugProperty2,
    public IXProperty
{
public:
	CDebugProperty();
	virtual ~CDebugProperty();

DECLARE_REGISTRY_RESOURCEID(IDR_DEBUGPROPERTY)

BEGIN_COM_MAP(CDebugProperty)
	COM_INTERFACE_ENTRY(IDebugProperty2)
    COM_INTERFACE_ENTRY(IXProperty)
END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

IMPLEMENT_CREATE(CDebugProperty, IXProperty)

	HRESULT FinalConstruct();
	void FinalRelease();

    STDMETHOD(Initialize)( IUnknown *pSymbol, DWORD dwStackBase, IUnknown *pSelfPtr, IUnknown *pOwnerPtr, DWORD dwType ); // actually pointer to Symbol is passed
    STDMETHOD(AddProperty)( IDebugProperty2 *pProperty ); // actually internal CPropertyInfo passed!
    STDMETHOD(GetSymbol)( IUnknown **ppOut ); // actually Symbol is returned!

public:
    STDMETHOD(GetPropertyInfo)( DEBUGPROP_INFO_FLAGS dwFields, DWORD dwRadix, DWORD dwTimeout, IDebugReference2 **rgpArgs, DWORD dwArgCount, DEBUG_PROPERTY_INFO *pPropertyInfo );
    STDMETHOD(SetValueAsString)( LPCOLESTR pszValue,DWORD dwRadix, DWORD dwTimeout );
    STDMETHOD(SetValueAsReference)( IDebugReference2 **rgpArgs, DWORD dwArgCount, IDebugReference2 *pValue, DWORD dwTimeout );
    STDMETHOD(EnumChildren)( DEBUGPROP_INFO_FLAGS dwFields, DWORD dwRadix, REFGUID guidFilter, DBG_ATTRIB_FLAGS dwAttribFilter, LPCOLESTR pszNameFilter, DWORD dwTimeout, IEnumDebugPropertyInfo2 **ppEnum );
    STDMETHOD(GetParent)( IDebugProperty2 **ppParent );
    STDMETHOD(GetDerivedMostProperty)( IDebugProperty2 **ppDerivedMost );
    STDMETHOD(GetMemoryBytes)( IDebugMemoryBytes2 **ppMemoryBytes );
    STDMETHOD(GetMemoryContext)( IDebugMemoryContext2 **ppMemory );
    STDMETHOD(GetSize)( DWORD *pdwSize );
    STDMETHOD(GetReference)( IDebugReference2 **ppReference );
    STDMETHOD(GetExtendedInfo)( REFGUID guidExtendedInfo, VARIANT *pExtendedInfo );

private:
    void FormatRegister( const XortElement& xCell, int iIndex, UINT nRadix, DEBUG_PROPERTY_INFO *pProp );
    xobject * findSelfPointer( Symbol *pSymbol );

    CComPtr<IXProperty>  m_spParent;
    DWORD                m_dwType;      // ty of the property: stack register or local variable
    Symbol              *m_pSymbol;     // debug symbol that represents this property
    xobject             *m_pSelf;       // this/self pointer to the runtime object if any
    xobject             *m_pOwner;      // pointer to the object that owns this member
    DWORD                m_dwStackBase; // stack base associated with this symbol if symbol is local variable

    PROPERTIES_LIST      m_listProperties; // stack registers
};

OBJECT_ENTRY_AUTO(__uuidof(DebugProperty), CDebugProperty)
